package element.synt;

import ast.AstItem;
import ast.ComplexDataSignature;
import ast.DataSignature;
import ast.Expression;
import element.base.BaseNode;
import element.base.Synt;
import element.base.WordType;

import java.util.List;

public class ComplexUnaryExp extends Synt {
    @Override
    public AstItem toAst() {
        if (getNodes().size() == 1) {
            AstItem item = ((LVal) getNodes().getFirst()).toAst();
            DataSignature signature = (DataSignature) item;
            Expression expression = new Expression();
            expression.operator = Expression.OperatorType.OP_ATOM;
            expression.operands.add(signature);
            expression.allUnaryExp.add(expression);
            return expression;
        } else {
            AstItem item = ((LVal) getNodes().getFirst()).toAst();
            DataSignature signature = (DataSignature) item;
            ComplexPFix complexPFix = (ComplexPFix) getNodes().getLast();
//            System.out.println(complexPFix.getNodes());
//            System.out.println();
            if (signature.type == DataSignature.DataType.COMPLEX) {
                if (((ComplexDataSignature) signature).opType == ComplexDataSignature.operationType.CLASS_ATTR) {
                    ((ComplexDataSignature) signature).opType = ComplexDataSignature.operationType.CLASS_METHOD;
                }
            }
            signature = addCPFix(signature, complexPFix);
            Expression expression = new Expression();
            expression.operator = Expression.OperatorType.OP_ATOM;
            expression.operands.add(signature);
            expression.allUnaryExp.add(expression);
            return expression;
        }
    }

    private ComplexDataSignature addCPFix(DataSignature signature, ComplexPFix cPFix) {

//        System.out.println(cPFix);
//        System.out.println();

        FuncPFix funcPFix = (FuncPFix) cPFix.getNodes().getFirst();

        ComplexDataSignature data = new ComplexDataSignature();
        data.type = DataSignature.DataType.COMPLEX;

        for (BaseNode node: funcPFix.getNodes()) {
            if (node.isSynt(FuncRParams.class)) {
                FuncRParams params = (FuncRParams) node;
                List<AstItem> paramList = params.toAsts();
                if (data.opType == null) {
                    data.dataOperated = signature;
                } else {
                    ComplexDataSignature _data = data;
                    data = new ComplexDataSignature();
                    data.dataOperated = _data;
                    data.type = DataSignature.DataType.COMPLEX;
                }
                data.opType = ComplexDataSignature.operationType.CALL_FUNC;
                for (AstItem item: paramList) {
                    data.operation.add(item);
                }
            } else if (node.isWord(WordType.LPARENT) && funcPFix.getNodes().get(funcPFix.getNodes().indexOf(node) + 1).isWord(WordType.RPARENT)) {
                if (data.opType == null) {
                    data.dataOperated = signature;
                } else {
                    ComplexDataSignature _data = data;
                    data = new ComplexDataSignature();
                    data.dataOperated = _data;
                    data.type = DataSignature.DataType.COMPLEX;
                }
                data.opType = ComplexDataSignature.operationType.CALL_FUNC;
            }
        }

        int point = 1;

        if (cPFix.getNodes().size() > point) {
            if (cPFix.getNodes().get(point).isSynt(ArrayPFix.class)) {
                ArrayPFix arrayPFix = (ArrayPFix) cPFix.getNodes().get(point);
                List<AstItem> indexes = arrayPFix.toAsts();
                ComplexDataSignature _data = data;
                data = new ComplexDataSignature();
                data.dataOperated = _data;
                data.type = DataSignature.DataType.COMPLEX;

                data.opType = ComplexDataSignature.operationType.ARRAY_LOC;
                for (AstItem item: indexes) {
                    data.operation.add(item);
                }
                point++;
            }
        }

        if (cPFix.getNodes().size() > point) {
            if (cPFix.getNodes().get(point).isSynt(ClassPFix.class)) {
                ClassPFix classPFix = (ClassPFix) cPFix.getNodes().get(point);
                LVal pFix = (LVal) classPFix.getNodes().getLast();

                DataSignature pFixData = (DataSignature) pFix.toAst();
                if (pFixData.type == DataSignature.DataType.PRIMARY) {
                    ComplexDataSignature _data = data;
                    data = new ComplexDataSignature();
                    data.dataOperated = _data;
                    data.type = DataSignature.DataType.COMPLEX;
                    data.opType = ComplexDataSignature.operationType.CLASS_ATTR;
                    data.operation.add(pFixData);
                } else {
                    DataSignature pFixHead = ((ComplexDataSignature) pFixData).dataOperated;
                    ComplexDataSignature tmpData = (ComplexDataSignature) pFixData;

                    while (pFixHead instanceof ComplexDataSignature) {
                        tmpData = (ComplexDataSignature) pFixHead;
                        pFixHead = tmpData.dataOperated;
                    }

                    ComplexDataSignature _data = data;
                    data = new ComplexDataSignature();
                    data.dataOperated = _data;
                    data.type = DataSignature.DataType.COMPLEX;
                    data.opType = ComplexDataSignature.operationType.CLASS_ATTR;
                    data.operation.add(pFixHead);
                    tmpData.dataOperated = data;
                    data = (ComplexDataSignature) pFixData;
                }
                point++;
            }
        }

        if (cPFix.getNodes().size() > point) {
            if (data.opType == ComplexDataSignature.operationType.CLASS_ATTR) {
                data.opType = ComplexDataSignature.operationType.CLASS_METHOD;
            }

            ComplexPFix nextPFix = (ComplexPFix) cPFix.getNodes().get(point);
            data = addCPFix(data, nextPFix);
        }

        return data;
    }
}
